home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / zmodem-part3-unix.shar / rz.c next >
C/C++ Source or Header  |  1993-10-23  |  32KB  |  1,544 lines

  1. #define VERSION "3.00 4-19-89"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox -DMD rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  * To compile on VMS:
  19.  *
  20.  *    define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  21.  *    cc rz.c
  22.  *    cc vvmodem.c
  23.  *    link rz,vvmodem
  24.  *    rz :== $disk:[username.subdir]rz.exe
  25.  *      For high speed, try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256.
  26.  *
  27.  *
  28.  *  Unix is a trademark of Western Electric Company
  29.  *
  30.  * A program for Unix to receive files and commands from computers running
  31.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  32.  *  rz uses Unix buffered input to reduce wasted CPU time.
  33.  *
  34.  *    This version implements ZMODEM Run Length Encoding 
  35.  *    and variable length headers.  These features were not funded
  36.  *    by the original Telenet development contract.  This software,
  37.  *    including these features, may be freely used for non
  38.  *    commercial and educational purposes.  This software may also
  39.  *    be freely used to support file transfer operations to or from
  40.  *    licensed Omen Technology products.  Contact Omen Technology
  41.  *    for licensing for other uses.  Any programs which use part or
  42.  *    all of this software must be provided in source form with this
  43.  *    notice intact except by written permission from Omen
  44.  *    Technology Incorporated.
  45.  *
  46.  *        Omen Technology Inc        FAX: 503-621-3745
  47.  *        Post Office Box 4681
  48.  *        Portland OR 97208
  49.  *
  50.  *    Previous versions of this program (not containing the extensions
  51.  *    listed above) remain in the public domain.
  52.  *
  53.  *    This code is made available in the hope it will be useful,
  54.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  55.  *    DAMAGES OF ANY KIND.
  56.  *
  57.  *
  58.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  59.  * "COMMAND filename"  (Unix only)
  60.  *
  61.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  62.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  63.  *  character reads for these systems. Added 7-01-84 CAF
  64.  *
  65.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  66.  *
  67.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  68.  *  Byte Information Exchange.
  69.  *
  70.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  71.  *  doesn't work properly (even though it compiles without error!),
  72.  *
  73.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  74.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  75.  *
  76.  *  VMS flavor hacks begin with rz version 2.00
  77.  *
  78.  *  -DMD may be added to compiler command line to compile in
  79.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  80.  *
  81.  *  HOWMANY may be tuned for best performance
  82.  *
  83.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  84.  */
  85.  
  86. #ifdef vax11c
  87. #include <types.h>
  88. #include <stat.h>
  89. #define LOGFILE "rzlog.tmp"
  90. #include <stdio.h>
  91. #include <signal.h>
  92. #include <setjmp.h>
  93. #include <ctype.h>
  94. #include <errno.h>
  95. #define OS "VMS"
  96. #define BUFREAD
  97. extern int errno;
  98. #define SS_NORMAL SS$_NORMAL
  99.  
  100. #ifndef PROGNAME
  101. #define PROGNAME "rz"
  102. #endif
  103.  
  104.  
  105. #else
  106.  
  107.  
  108. #define SS_NORMAL 0
  109. #define LOGFILE "/tmp/rzlog"
  110. #include <stdio.h>
  111. #include <signal.h>
  112. #include <setjmp.h>
  113. #include <ctype.h>
  114. #include <errno.h>
  115. extern int errno;
  116. FILE *popen();
  117. #endif
  118.  
  119. #define OK 0
  120. #define FALSE 0
  121. #define TRUE 1
  122. #define ERROR (-1)
  123.  
  124. /*
  125.  * Max value for HOWMANY is 255.
  126.  *   A larger value reduces system overhead but may evoke kernel bugs.
  127.  *   133 corresponds to an XMODEM/CRC sector
  128.  */
  129. #ifndef HOWMANY
  130. #define HOWMANY 133
  131. #endif
  132.  
  133. /* Ward Christensen / CP/M parameters - Don't change these! */
  134. #define ENQ 005
  135. #define CAN ('X'&037)
  136. #define XOFF ('s'&037)
  137. #define XON ('q'&037)
  138. #define SOH 1
  139. #define STX 2
  140. #define EOT 4
  141. #define ACK 6
  142. #define NAK 025
  143. #define CPMEOF 032
  144. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  145. #define TIMEOUT (-2)
  146. #define RCDO (-3)
  147. #define GCOUNT (-4)
  148. #define ERRORMAX 5
  149. #define RETRYMAX 5
  150. #define WCEOT (-10)
  151. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  152. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  153.  
  154. int Zmodem=0;        /* ZMODEM protocol requested */
  155. int Nozmodem = 0;    /* If invoked as "rb" */
  156. unsigned Baudrate = 2400;
  157. unsigned Effbaud = 2400;
  158. #ifdef vax11c
  159. #include "vrzsz.c"    /* most of the system dependent stuff here */
  160. #else
  161. #include "rbsb.c"    /* most of the system dependent stuff here */
  162. #endif
  163. #include "crctab.c"
  164.  
  165. char *substr();
  166. FILE *fout;
  167.  
  168. /*
  169.  * Routine to calculate the free bytes on the current file system
  170.  *  ~0 means many free bytes (unknown)
  171.  */
  172. long getfree()
  173. {
  174.     return(~0L);    /* many free bytes ... */
  175. }
  176.  
  177. int Lastrx;
  178. int Crcflg;
  179. int Firstsec;
  180. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  181. int errors;
  182. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  183. #ifdef ONEREAD
  184. /* Sorry, Regulus and some others don't work right in raw mode! */
  185. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  186. #else
  187. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  188. #endif
  189.  
  190. #define DEFBYTL 2000000000L    /* default rx file size */
  191. long Bytesleft;        /* number of bytes of incoming file left */
  192. long Modtime;        /* Unix style mod time for incoming file */
  193. int Filemode;        /* Unix style mode for incoming file */
  194. char Pathname[PATHLEN];
  195. char *Progname;        /* the name by which we were called */
  196.  
  197. int Batch=0;
  198. int Topipe=0;
  199. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  200. int Verbose=0;
  201. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  202. int Nflag = 0;        /* Don't really transfer files */
  203. int Rxclob=FALSE;    /* Clobber existing file */
  204. int Rxbinary=FALSE;    /* receive all files in bin mode */
  205. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  206. int Thisbinary;        /* current file is to be received in bin mode */
  207. int Blklen;        /* record length of received packets */
  208.  
  209. #ifdef SEGMENTS
  210. int chinseg = 0;    /* Number of characters received in this data seg */
  211. char secbuf[1+(SEGMENTS+1)*1024];
  212. #else
  213. char secbuf[1025];
  214. #endif
  215.  
  216.  
  217. char linbuf[HOWMANY];
  218. int Lleft=0;        /* number of characters in linbuf */
  219. time_t timep[2];
  220. char Lzmanag;        /* Local file management request */
  221. char zconv;        /* ZMODEM file conversion request */
  222. char zmanag;        /* ZMODEM file management request */
  223. char ztrans;        /* ZMODEM file transport request */
  224. int Zctlesc;        /* Encode control characters */
  225. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  226.  
  227. jmp_buf tohere;        /* For the interrupt on RX timeout */
  228.  
  229. #define xsendline(c) sendline(c)
  230.  
  231. #include "zm.c"
  232.  
  233. #include "zmr.c"
  234.  
  235. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to
  236. Last rx close */
  237.  
  238. alrm()
  239. {
  240.     longjmp(tohere, -1);
  241. }
  242.  
  243. /* called by signal interrupt or terminate to clean things up */
  244. bibi(n)
  245. {
  246.     if (Zmodem)
  247.         zmputs(Attn);
  248.     canit(); mode(0);
  249.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  250.     cucheck();
  251.     exit(128+n);
  252. }
  253.  
  254. main(argc, argv)
  255. char *argv[];
  256. {
  257.     register char *cp;
  258.     register npats;
  259.     char *virgin, **patts;
  260.     char *getenv();
  261.     int exitcode;
  262.  
  263.     Rxtimeout = 100;
  264.     setbuf(stderr, NULL);
  265.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  266.         Restricted=TRUE;
  267.  
  268.     from_cu();
  269. #ifdef vax11c
  270.     chkinvok(virgin = PROGNAME);
  271. #else
  272.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  273. #endif
  274.     npats = 0;
  275.     while (--argc) {
  276.         cp = *++argv;
  277.         if (*cp == '-') {
  278.             while( *++cp) {
  279.                 switch(*cp) {
  280.                 case '\\':
  281.                      cp[1] = toupper(cp[1]);  continue;
  282.                 case '+':
  283.                     Lzmanag = ZMAPND; break;
  284.                 case 'a':
  285.                     Rxascii=TRUE;  break;
  286.                 case 'b':
  287.                     Rxbinary=TRUE; break;
  288.                 case 'c':
  289.                     Crcflg=TRUE; break;
  290. #ifndef vax11c
  291.                 case 'D':
  292.                     Nflag = TRUE; break;
  293. #endif
  294.                 case 'e':
  295.                     Zctlesc = 1; break;
  296.                 case 'p':
  297.                     Lzmanag = ZMPROT;  break;
  298.                 case 'q':
  299.                     Quiet=TRUE; Verbose=0; break;
  300.                 case 't':
  301.                     if (--argc < 1) {
  302.                         usage();
  303.                     }
  304.                     Rxtimeout = atoi(*++argv);
  305.                     if (Rxtimeout<10 || Rxtimeout>1000)
  306.                         usage();
  307.                     break;
  308.                 case 'w':
  309.                     if (--argc < 1) {
  310.                         usage();
  311.                     }
  312.                     Zrwindow = atoi(*++argv);
  313.                     break;
  314.                 case 'u':
  315.                     MakeLCPathname=FALSE; break;
  316.                 case 'v':
  317.                     ++Verbose; break;
  318.                 case 'y':
  319.                     Rxclob=TRUE; break;
  320.                 default:
  321.                     usage();
  322.                 }
  323.             }
  324.         }
  325.         else if ( !npats && argc>0) {
  326.             if (argv[0][0]) {
  327.                 npats=argc;
  328.                 patts=argv;
  329.             }
  330.         }
  331.     }
  332.     if (npats > 1)
  333.         usage();
  334.     if (Batch && npats)
  335.         usage();
  336.     if (Verbose) {
  337.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  338.             printf("Can't open log file %s\n",LOGFILE);
  339.             exit(0200);
  340.         }
  341.         setbuf(stderr, NULL);
  342.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  343.     }
  344.     if (Fromcu && !Quiet) {
  345.         if (Verbose == 0)
  346.             Verbose = 2;
  347.     }
  348.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  349.     mode(1);
  350.     if (signal(SIGINT, bibi) == SIG_IGN) {
  351.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  352.     }
  353.     else {
  354.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  355.     }
  356.     signal(SIGTERM, bibi);
  357.     if (wcreceive(npats, patts)==ERROR) {
  358.         exitcode=0200;
  359.         canit();
  360.     }
  361.     mode(0);
  362.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  363.         canit();
  364.     if (exitcode)
  365.         cucheck();
  366.     exit(exitcode ? exitcode:SS_NORMAL);
  367. }
  368.  
  369.  
  370. usage()
  371. {
  372.     cucheck();
  373.     fprintf(stderr,"Usage:    rz [-abeuvy]        (ZMODEM)\n");
  374.     fprintf(stderr,"or    rb [-abuvy]        (YMODEM)\n");
  375.     fprintf(stderr,"or    rx [-abcv] file    (XMODEM or XMODEM-1k)\n");
  376.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  377.     fprintf(stderr,"      -b Binary transfer for all files\n");
  378. #ifndef vax11c
  379.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  380. #endif
  381.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  382.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  383.     fprintf(stderr,"      -y Yes, clobber existing file if any\n");
  384.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  385.       Progname, VERSION, OS);
  386.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  387.     exit(SS_NORMAL);
  388. }
  389. /*
  390.  *  Debugging information output interface routine
  391.  */
  392. /* VARARGS1 */
  393. vfile(f, a, b, c)
  394. register char *f;
  395. {
  396.     if (Verbose > 2) {
  397.         fprintf(stderr, f, a, b, c);
  398.         fprintf(stderr, "\n");
  399.     }
  400. }
  401.  
  402. /*
  403.  * Let's receive something already.
  404.  */
  405.  
  406. char *rbmsg =
  407. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  408.  
  409. wcreceive(argc, argp)
  410. char **argp;
  411. {
  412.     register c;
  413.  
  414.     if (Batch || argc==0) {
  415.         Crcflg=1;
  416.         if ( !Quiet)
  417.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  418.         if (c=tryz()) {
  419.             if (c == ZCOMPL)
  420.                 return OK;
  421.             if (c == ERROR)
  422.                 goto fubar;
  423.             c = rzfiles();
  424.             if (c)
  425.                 goto fubar;
  426.         } else {
  427.             for (;;) {
  428.                 if (wcrxpn(secbuf)== ERROR)
  429.                     goto fubar;
  430.                 if (secbuf[0]==0)
  431.                     return OK;
  432.                 if (procheader(secbuf) == ERROR)
  433.                     goto fubar;
  434.                 if (wcrx()==ERROR)
  435.                     goto fubar;
  436.             }
  437.         }
  438.     } else {
  439.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  440.  
  441.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  442.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  443.         if ((fout=fopen(Pathname, "w")) == NULL)
  444.             return ERROR;
  445.         if (wcrx()==ERROR)
  446.             goto fubar;
  447.     }
  448.     return OK;
  449. fubar:
  450.     canit();
  451. #ifndef vax11c
  452.     if (Topipe && fout) {
  453.         pclose(fout);  return ERROR;
  454.     }
  455. #endif
  456.     Modtime = 1;
  457.     if (fout)
  458.         fclose(fout);
  459. #ifndef vax11c
  460.     if (Restricted) {
  461.         unlink(Pathname);
  462.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  463.     }
  464. #endif
  465.     return ERROR;
  466. }
  467.  
  468.  
  469. /*
  470.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  471.  * Length is indeterminate as long as less than Blklen
  472.  * A null string represents no more files (YMODEM)
  473.  */
  474. wcrxpn(rpn)
  475. char *rpn;    /* receive a pathname */
  476. {
  477.     register c;
  478.  
  479. #ifdef NFGVMIN
  480.     readline(1);
  481. #else
  482.     purgeline();
  483. #endif
  484.  
  485. et_tu:
  486.     Firstsec=TRUE;  Eofseen=FALSE;
  487.     sendline(Crcflg?WANTCRC:NAK);
  488.     Lleft=0;    /* Do read next time ... */
  489.     while ((c = wcgetsec(rpn, 100)) != 0) {
  490.         if (c == WCEOT) {
  491.             zperr( "Pathname fetch returned %d", c);
  492.             sendline(ACK);
  493.             Lleft=0;    /* Do read next time ... */
  494.             readline(1);
  495.             goto et_tu;
  496.         }
  497.         return ERROR;
  498.     }
  499.     sendline(ACK);
  500.     return OK;
  501. }
  502.  
  503. /*
  504.  * Adapted from CMODEM13.C, written by
  505.  * Jack M. Wierda and Roderick W. Hart
  506.  */
  507.  
  508. wcrx()
  509. {
  510.     register int sectnum, sectcurr;
  511.     register char sendchar;
  512.     register char *p;
  513.     int cblklen;            /* bytes to dump this block */
  514.  
  515.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  516.     sendchar=Crcflg?WANTCRC:NAK;
  517.  
  518.     for (;;) {
  519.         sendline(sendchar);    /* send it now, we're ready! */
  520.         Lleft=0;    /* Do read next time ... */
  521.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  522.         report(sectcurr);
  523.         if (sectcurr==(sectnum+1 &0377)) {
  524.             sectnum++;
  525.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  526.             if (putsec(secbuf, cblklen)==ERROR)
  527.                 return ERROR;
  528.             if ((Bytesleft-=cblklen) < 0)
  529.                 Bytesleft = 0;
  530.             sendchar=ACK;
  531.         }
  532.         else if (sectcurr==(sectnum&0377)) {
  533.             zperr( "Received dup Sector");
  534.             sendchar=ACK;
  535.         }
  536.         else if (sectcurr==WCEOT) {
  537.             if (closeit())
  538.                 return ERROR;
  539.             sendline(ACK);
  540.             Lleft=0;    /* Do read next time ... */
  541.             return OK;
  542.         }
  543.         else if (sectcurr==ERROR)
  544.             return ERROR;
  545.         else {
  546.             zperr( "Sync Error");
  547.             return ERROR;
  548.         }
  549.     }
  550. }
  551.  
  552. /*
  553.  * Wcgetsec fetches a Ward Christensen type sector.
  554.  * Returns sector number encountered or ERROR if valid sector not received,
  555.  * or CAN CAN received
  556.  * or WCEOT if eot sector
  557.  * time is timeout for first char, set to 4 seconds thereafter
  558.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  559.  *    (Caller must do that when he is good and ready to get next sector)
  560.  */
  561.  
  562. wcgetsec(rxbuf, maxtime)
  563. char *rxbuf;
  564. int maxtime;
  565. {
  566.     register checksum, wcj, firstch;
  567.     register unsigned short oldcrc;
  568.     register char *p;
  569.     int sectcurr;
  570.  
  571.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  572.  
  573.         if ((firstch=readline(maxtime))==STX) {
  574.             Blklen=1024; goto get2;
  575.         }
  576.         if (firstch==SOH) {
  577.             Blklen=128;
  578. get2:
  579.             sectcurr=readline(1);
  580.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  581.                 oldcrc=checksum=0;
  582.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  583.                     if ((firstch=readline(1)) < 0)
  584.                         goto bilge;
  585.                     oldcrc=updcrc(firstch, oldcrc);
  586.                     checksum += (*p++ = firstch);
  587.                 }
  588.                 if ((firstch=readline(1)) < 0)
  589.                     goto bilge;
  590.                 if (Crcflg) {
  591.                     oldcrc=updcrc(firstch, oldcrc);
  592.                     if ((firstch=readline(1)) < 0)
  593.                         goto bilge;
  594.                     oldcrc=updcrc(firstch, oldcrc);
  595.                     if (oldcrc & 0xFFFF)
  596.                         zperr( "CRC");
  597.                     else {
  598.                         Firstsec=FALSE;
  599.                         return sectcurr;
  600.                     }
  601.                 }
  602.                 else if (((checksum-firstch)&0377)==0) {
  603.                     Firstsec=FALSE;
  604.                     return sectcurr;
  605.                 }
  606.                 else
  607.                     zperr( "Checksum");
  608.             }
  609.             else
  610.                 zperr("Sector number garbled");
  611.         }
  612.         /* make sure eot really is eot and not just mixmash */
  613. #ifdef NFGVMIN
  614.         else if (firstch==EOT && readline(1)==TIMEOUT)
  615.             return WCEOT;
  616. #else
  617.         else if (firstch==EOT && Lleft==0)
  618.             return WCEOT;
  619. #endif
  620.         else if (firstch==CAN) {
  621.             if (Lastrx==CAN) {
  622.                 zperr( "Sender CANcelled");
  623.                 return ERROR;
  624.             } else {
  625.                 Lastrx=CAN;
  626.                 continue;
  627.             }
  628.         }
  629.         else if (firstch==TIMEOUT) {
  630.             if (Firstsec)
  631.                 goto humbug;
  632. bilge:
  633.             zperr( "TIMEOUT");
  634.         }
  635.         else
  636.             zperr( "Got 0%o sector header", firstch);
  637.  
  638. humbug:
  639.         Lastrx=0;
  640.         while(readline(1)!=TIMEOUT)
  641.             ;
  642.         if (Firstsec) {
  643.             sendline(Crcflg?WANTCRC:NAK);
  644.             Lleft=0;    /* Do read next time ... */
  645.         } else {
  646.             maxtime=40; sendline(NAK);
  647.             Lleft=0;    /* Do read next time ... */
  648.         }
  649.     }
  650.     /* try to stop the bubble machine. */
  651.     canit();
  652.     return ERROR;
  653. }
  654.  
  655. #ifndef vax11c
  656. /*
  657.  * This version of readline is reasoably well suited for
  658.  * reading many characters.
  659.  *  (except, currently, for the Regulus version!)
  660.  *
  661.  * timeout is in tenths of seconds
  662.  */
  663. readline(timeout)
  664. int timeout;
  665. {
  666.     register n;
  667.     static char *cdq;    /* pointer for removing chars from linbuf */
  668.  
  669.     if (--Lleft >= 0) {
  670.         if (Verbose > 8) {
  671.             fprintf(stderr, "%02x ", *cdq&0377);
  672.         }
  673.         return (*cdq++ & 0377);
  674.     }
  675.     n = timeout/10;
  676.     if (n < 2)
  677.         n = 3;
  678.     if (Verbose > 5)
  679.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  680.           n, Readnum);
  681.     if (setjmp(tohere)) {
  682. #ifdef TIOCFLUSH
  683. /*        ioctl(0, TIOCFLUSH, 0); */
  684. #endif
  685.         Lleft = 0;
  686.         if (Verbose>1)
  687.             fprintf(stderr, "Readline:TIMEOUT\n");
  688.         return TIMEOUT;
  689.     }
  690.     signal(SIGALRM, alrm); alarm(n);
  691.     Lleft=read(0, cdq=linbuf, Readnum);
  692.     alarm(0);
  693.     if (Verbose > 5) {
  694.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  695.     }
  696.     if (Lleft < 1)
  697.         return TIMEOUT;
  698.     --Lleft;
  699.     if (Verbose > 8) {
  700.         fprintf(stderr, "%02x ", *cdq&0377);
  701.     }
  702.     return (*cdq++ & 0377);
  703. }
  704.  
  705.  
  706.  
  707. /*
  708.  * Purge the modem input queue of all characters
  709.  */
  710. purgeline()
  711. {
  712.     Lleft = 0;
  713. #ifdef USG
  714.     ioctl(0, TCFLSH, 0);
  715. #else
  716.     lseek(0, 0L, 2);
  717. #endif
  718. }
  719. #endif
  720.  
  721.  
  722. /*
  723.  * Process incoming file information header
  724.  */
  725. procheader(name)
  726. char *name;
  727. {
  728.     register char *openmode, *p, **pp;
  729.  
  730.     /* set default parameters and overrides */
  731.     openmode = "w";
  732.     Thisbinary = (!Rxascii) || Rxbinary;
  733.     if (Lzmanag)
  734.         zmanag = Lzmanag;
  735.  
  736.     /*
  737.      *  Process ZMODEM remote file management requests
  738.      */
  739.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  740.         Thisbinary = 0;
  741.     if (zconv == ZCBIN)    /* Remote Binary override */
  742.         Thisbinary = TRUE;
  743.     else if (zmanag == ZMAPND)
  744.         openmode = "a";
  745.  
  746. #ifndef BIX
  747.     /* Check for existing file */
  748.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
  749.         fclose(fout);  return ERROR;
  750.     }
  751. #endif
  752.  
  753.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  754.  
  755.     p = name + 1 + strlen(name);
  756.     if (*p) {    /* file coming from Unix or DOS system */
  757.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  758. #ifndef vax11c
  759.         if (Filemode & UNIXFILE)
  760.             ++Thisbinary;
  761. #endif
  762.         if (Verbose) {
  763.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  764.               name, Bytesleft, Modtime, Filemode);
  765.         }
  766.     }
  767.  
  768. #ifdef BIX
  769.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  770.         return ERROR;
  771.     return OK;
  772. #else
  773.  
  774.     else {        /* File coming from CP/M system */
  775.         for (p=name; *p; ++p)        /* change / to _ */
  776.             if ( *p == '/')
  777.                 *p = '_';
  778.  
  779.         if ( *--p == '.')        /* zap trailing period */
  780.             *p = 0;
  781.     }
  782.  
  783. #ifndef vax11c
  784.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
  785.       && !(Filemode&UNIXFILE))
  786.         uncaps(name);
  787. #endif
  788.     if (Topipe > 0) {
  789.         sprintf(Pathname, "%s %s", Progname+2, name);
  790.         if (Verbose)
  791.             fprintf(stderr,  "Topipe: %s %s\n",
  792.               Pathname, Thisbinary?"BIN":"ASCII");
  793. #ifndef vax11c
  794.         if ((fout=popen(Pathname, "w")) == NULL)
  795.             return ERROR;
  796. #endif
  797.     } else {
  798.         strcpy(Pathname, name);
  799.         if (Verbose) {
  800.             fprintf(stderr,  "Receiving %s %s %s\n",
  801.               name, Thisbinary?"BIN":"ASCII", openmode);
  802.         }
  803.         checkpath(name);
  804.         if (Nflag)
  805.             name = "/dev/null";
  806. #ifndef vax11c
  807.         if (name[0] == '!' || name[0] == '|') {
  808.             if ( !(fout = popen(name+1, "w"))) {
  809.                 return ERROR;
  810.             }
  811.             Topipe = -1;  return(OK);
  812.         }
  813. #endif
  814. #ifdef MD
  815.         fout = fopen(name, openmode);
  816.         if ( !fout)
  817.             if (make_dirs(name))
  818.                 fout = fopen(name, openmode);
  819. #else
  820.         fout = fopen(name, openmode);
  821. #endif
  822.         if ( !fout)
  823.             return ERROR;
  824.     }
  825.     return OK;
  826. #endif /* BIX */
  827. }
  828.  
  829. #ifdef MD
  830. /*
  831.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  832.  */
  833.  
  834. /*
  835.  * After a file/link/symlink/dir creation has failed, see if
  836.  * it's because some required directory was not present, and if
  837.  * so, create all required dirs.
  838.  */
  839. make_dirs(pathname)
  840. register char *pathname;
  841. {
  842.     register char *p;        /* Points into path */
  843.     int madeone = 0;        /* Did we do anything yet? */
  844.     int save_errno = errno;        /* Remember caller's errno */
  845.     char *strchr();
  846.  
  847.     if (errno != ENOENT)
  848.         return 0;        /* Not our problem */
  849.  
  850.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  851.         /* Avoid mkdir of empty string, if leading or double '/' */
  852.         if (p == pathname || p[-1] == '/')
  853.             continue;
  854.         /* Avoid mkdir where last part of path is '.' */
  855.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  856.             continue;
  857.         *p = 0;                /* Truncate the path there */
  858.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  859.             vfile("Made directory %s\n", pathname);
  860.             madeone++;        /* Remember if we made one */
  861.             *p = '/';
  862.             continue;
  863.         }
  864.         *p = '/';
  865.         if (errno == EEXIST)        /* Directory already exists */
  866.             continue;
  867.         /*
  868.          * Some other error in the mkdir.  We return to the caller.
  869.          */
  870.         break;
  871.     }
  872.     errno = save_errno;        /* Restore caller's errno */
  873.     return madeone;            /* Tell them to retry if we made one */
  874. }
  875.  
  876. #if (MD != 2)
  877. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  878. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  879. #define TERM_VALUE(status)    ((status) >> 8)
  880. /*
  881.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  882.  */
  883. mkdir(dpath, dmode)
  884. char *dpath;
  885. int dmode;
  886. {
  887.     int cpid, status;
  888.     struct stat statbuf;
  889.  
  890.     if (stat(dpath,&statbuf) == 0) {
  891.         errno = EEXIST;        /* Stat worked, so it already exists */
  892.         return -1;
  893.     }
  894.  
  895.     /* If stat fails for a reason other than non-existence, return error */
  896.     if (errno != ENOENT) return -1; 
  897.  
  898.     switch (cpid = fork()) {
  899.  
  900.     case -1:            /* Error in fork() */
  901.         return(-1);        /* Errno is set already */
  902.  
  903.     case 0:                /* Child process */
  904.         /*
  905.          * Cheap hack to set mode of new directory.  Since this
  906.          * child process is going away anyway, we zap its umask.
  907.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  908.          * directory.  Does anybody care?
  909.          */
  910.         status = umask(0);    /* Get current umask */
  911.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  912.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  913.         _exit(-1);        /* Can't exec /bin/mkdir */
  914.     
  915.     default:            /* Parent process */
  916.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  917.     }
  918.  
  919.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  920.         errno = EIO;        /* We don't know why, but */
  921.         return -1;        /* /bin/mkdir failed */
  922.     }
  923.  
  924.     return 0;
  925. }
  926. #endif /* MD != 2 */
  927. #endif /* MD */
  928.  
  929. /*
  930.  * Putsec writes the n characters of buf to receive file fout.
  931.  *  If not in binary mode, carriage returns, and all characters
  932.  *  starting with CPMEOF are discarded.
  933.  */
  934. putsec(buf, n)
  935. char *buf;
  936. register n;
  937. {
  938.     register char *p;
  939.  
  940.     if (n == 0)
  941.         return OK;
  942.     if (Thisbinary) {
  943.         for (p=buf; --n>=0; )
  944.             putc( *p++, fout);
  945.     }
  946.     else {
  947.         if (Eofseen)
  948.             return OK;
  949.         for (p=buf; --n>=0; ++p ) {
  950.             if ( *p == '\r')
  951.                 continue;
  952.             if (*p == CPMEOF) {
  953.                 Eofseen=TRUE; return OK;
  954.             }
  955.             putc(*p ,fout);
  956.         }
  957.     }
  958.     return OK;
  959. }
  960.  
  961. #ifndef vax11c
  962. /*
  963.  *  Send a character to modem.  Small is beautiful.
  964.  */
  965. sendline(c)
  966. {
  967.     char d;
  968.  
  969.     d = c;
  970.     if (Verbose>6)
  971.         fprintf(stderr, "Sendline: %x\n", c);
  972.     write(1, &d, 1);
  973. }
  974.  
  975. flushmo() {}
  976. #endif
  977.  
  978.  
  979.  
  980.  
  981.  
  982. /* make string s lower case */
  983. uncaps(s)
  984. register char *s;
  985. {
  986.     for ( ; *s; ++s)
  987.         if (isupper(*s))
  988.             *s = tolower(*s);
  989. }
  990. /*
  991.  * IsAnyLower returns TRUE if string s has lower case letters.
  992.  */
  993. IsAnyLower(s)
  994. register char *s;
  995. {
  996.     for ( ; *s; ++s)
  997.         if (islower(*s))
  998.             return TRUE;
  999.     return FALSE;
  1000. }
  1001.  
  1002. /*
  1003.  * substr(string, token) searches for token in string s
  1004.  * returns pointer to token within string if found, NULL otherwise
  1005.  */
  1006. char *
  1007. substr(s, t)
  1008. register char *s,*t;
  1009. {
  1010.     register char *ss,*tt;
  1011.     /* search for first char of token */
  1012.     for (ss=s; *s; s++)
  1013.         if (*s == *t)
  1014.             /* compare token with substring */
  1015.             for (ss=s,tt=t; ;) {
  1016.                 if (*tt == 0)
  1017.                     return s;
  1018.                 if (*ss++ != *tt++)
  1019.                     break;
  1020.             }
  1021.     return NULL;
  1022. }
  1023.  
  1024. /*
  1025.  * Log an error
  1026.  */
  1027. /*VARARGS1*/
  1028. zperr(s,p,u)
  1029. char *s, *p, *u;
  1030. {
  1031.     if (Verbose <= 0)
  1032.         return;
  1033.     fprintf(stderr, "Retry %d: ", errors);
  1034.     fprintf(stderr, s, p, u);
  1035.     fprintf(stderr, "\n");
  1036. }
  1037.  
  1038. /* send cancel string to get the other end to shut up */
  1039. canit()
  1040. {
  1041.     static char canistr[] = {
  1042.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1043.     };
  1044.  
  1045. #ifdef vax11c
  1046.     raw_wbuf(strlen(canistr), canistr);
  1047.     purgeline();
  1048. #else
  1049.     printf(canistr);
  1050.     Lleft=0;    /* Do read next time ... */
  1051.     fflush(stdout);
  1052. #endif
  1053. }
  1054.  
  1055.  
  1056. report(sct)
  1057. int sct;
  1058. {
  1059.     if (Verbose>1)
  1060.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  1061. }
  1062.  
  1063. /*
  1064.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1065.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  1066.  * If called as rb use YMODEM protocol
  1067.  */
  1068. chkinvok(s)
  1069. char *s;
  1070. {
  1071.     register char *p;
  1072.  
  1073.     p = s;
  1074.     while (*p == '-')
  1075.         s = ++p;
  1076.     while (*p)
  1077.         if (*p++ == '/')
  1078.             s = p;
  1079.     if (*s == 'v') {
  1080.         Verbose=1; ++s;
  1081.     }
  1082.     Progname = s;
  1083.     if (s[0]=='r' && s[1]=='z')
  1084.         Batch = TRUE;
  1085.     if (s[0]=='r' && s[1]=='b')
  1086.         Batch = Nozmodem = TRUE;
  1087.     if (s[2] && s[0]=='r' && s[1]=='b')
  1088.         Topipe = 1;
  1089.     if (s[2] && s[0]=='r' && s[1]=='z')
  1090.         Topipe = 1;
  1091. }
  1092.  
  1093. /*
  1094.  * Totalitarian Communist pathname processing
  1095.  */
  1096. checkpath(name)
  1097. char *name;
  1098. {
  1099.     if (Restricted) {
  1100.         if (fopen(name, "r") != NULL) {
  1101.             canit();
  1102.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1103.             bibi(-1);
  1104.         }
  1105.         /* restrict pathnames to current tree or uucppublic */
  1106.         if ( substr(name, "../")
  1107.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1108.             canit();
  1109.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1110.             bibi(-1);
  1111.         }
  1112.     }
  1113. }
  1114.  
  1115. /*
  1116.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1117.  *  Handles ZSINIT frame
  1118.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1119.  *   ZCOMPL if transaction finished,  else 0
  1120.  */
  1121. tryz()
  1122. {
  1123.     register c, n;
  1124.     register cmdzack1flg;
  1125.  
  1126.     if (Nozmodem)        /* Check for "rb" program name */
  1127.         return 0;
  1128.  
  1129.  
  1130.     for (n=Zmodem?15:5; --n>=0; ) {
  1131.         /* Set buffer length (0) and capability flags */
  1132. #ifdef SEGMENTS
  1133.         stohdr(SEGMENTS*1024L);
  1134. #else
  1135.         stohdr(0L);
  1136. #endif
  1137. #ifdef CANBREAK
  1138.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1139. #else
  1140.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1141. #endif
  1142.         if (Zctlesc)
  1143.             Txhdr[ZF0] |= TESCCTL;
  1144.         Txhdr[ZF0] |= CANRLE;
  1145.         Txhdr[ZF1] = CANVHDR;
  1146.         /* tryzhdrtype may == ZRINIT */
  1147.         zshhdr(4,tryzhdrtype, Txhdr);
  1148.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1149.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1150. again:
  1151.         switch (zgethdr(Rxhdr, 0)) {
  1152.         case ZRQINIT:
  1153.             if (Rxhdr[ZF3] & 0x80)
  1154.                 Usevhdrs = 1;    /* we can var header */
  1155.             continue;
  1156.         case ZEOF:
  1157.             continue;
  1158.         case TIMEOUT:
  1159.             continue;
  1160.         case ZFILE:
  1161.             zconv = Rxhdr[ZF0];
  1162.             zmanag = Rxhdr[ZF1];
  1163.             ztrans = Rxhdr[ZF2];
  1164.             if (Rxhdr[ZF3] & ZCANVHDR)
  1165.                 Usevhdrs = TRUE;
  1166.             tryzhdrtype = ZRINIT;
  1167.             c = zrdata(secbuf, 1024);
  1168.             mode(3);
  1169.             if (c == GOTCRCW)
  1170.                 return ZFILE;
  1171.             zshhdr(4,ZNAK, Txhdr);
  1172.             goto again;
  1173.         case ZSINIT:
  1174.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1175.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1176.                 stohdr(1L);
  1177.                 zshhdr(4,ZACK, Txhdr);
  1178.                 goto again;
  1179.             }
  1180.             zshhdr(4,ZNAK, Txhdr);
  1181.             goto again;
  1182.         case ZFREECNT:
  1183.             stohdr(getfree());
  1184.             zshhdr(4,ZACK, Txhdr);
  1185.             goto again;
  1186.         case ZCOMMAND:
  1187. #ifdef vax11c
  1188.             return ERROR;
  1189. #else
  1190.             cmdzack1flg = Rxhdr[ZF0];
  1191.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1192.                 if (cmdzack1flg & ZCACK1)
  1193.                     stohdr(0L);
  1194.                 else
  1195.                     stohdr((long)sys2(secbuf));
  1196.                 purgeline();    /* dump impatient questions */
  1197.                 do {
  1198.                     zshhdr(4,ZCOMPL, Txhdr);
  1199.                 }
  1200.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1201.                 ackbibi();
  1202.                 if (cmdzack1flg & ZCACK1)
  1203.                     exec2(secbuf);
  1204.                 return ZCOMPL;
  1205.             }
  1206.             zshhdr(4,ZNAK, Txhdr); goto again;
  1207. #endif
  1208.         case ZCOMPL:
  1209.             goto again;
  1210.         default:
  1211.             continue;
  1212.         case ZFIN:
  1213.             ackbibi(); return ZCOMPL;
  1214.         case ZCAN:
  1215.             return ERROR;
  1216.         }
  1217.     }
  1218.     return 0;
  1219. }
  1220.  
  1221. /*
  1222.  * Receive 1 or more files with ZMODEM protocol
  1223.  */
  1224. rzfiles()
  1225. {
  1226.     register c;
  1227.  
  1228.     for (;;) {
  1229.         switch (c = rzfile()) {
  1230.         case ZEOF:
  1231.         case ZSKIP:
  1232.             switch (tryz()) {
  1233.             case ZCOMPL:
  1234.                 return OK;
  1235.             default:
  1236.                 return ERROR;
  1237.             case ZFILE:
  1238.                 break;
  1239.             }
  1240.             continue;
  1241.         default:
  1242.             return c;
  1243.         case ERROR:
  1244.             return ERROR;
  1245.         }
  1246.     }
  1247. }
  1248.  
  1249. /*
  1250.  * Receive a file with ZMODEM protocol
  1251.  *  Assumes file name frame is in secbuf
  1252.  */
  1253. rzfile()
  1254. {
  1255.     register c, n;
  1256.     long rxbytes;
  1257.  
  1258.     Eofseen=FALSE;
  1259.     if (procheader(secbuf) == ERROR) {
  1260.         return (tryzhdrtype = ZSKIP);
  1261.     }
  1262.  
  1263.     n = 20; rxbytes = 0l;
  1264.  
  1265.     for (;;) {
  1266. #ifdef SEGMENTS
  1267.         chinseg = 0;
  1268. #endif
  1269.         stohdr(rxbytes);
  1270.         zshhdr(4,ZRPOS, Txhdr);
  1271. nxthdr:
  1272.         switch (c = zgethdr(Rxhdr, 0)) {
  1273.         default:
  1274.             vfile("rzfile: zgethdr returned %d", c);
  1275.             return ERROR;
  1276.         case ZNAK:
  1277.         case TIMEOUT:
  1278. #ifdef SEGMENTS
  1279.             putsec(secbuf, chinseg);
  1280.             chinseg = 0;
  1281. #endif
  1282.             if ( --n < 0) {
  1283.                 vfile("rzfile: zgethdr returned %d", c);
  1284.                 return ERROR;
  1285.             }
  1286.         case ZFILE:
  1287.             zrdata(secbuf, 1024);
  1288.             continue;
  1289.         case ZEOF:
  1290. #ifdef SEGMENTS
  1291.             putsec(secbuf, chinseg);
  1292.             chinseg = 0;
  1293. #endif
  1294.             if (rclhdr(Rxhdr) != rxbytes) {
  1295.                 /*
  1296.                  * Ignore eof if it's at wrong place - force
  1297.                  *  a timeout because the eof might have gone
  1298.                  *  out before we sent our zrpos.
  1299.                  */
  1300.                 errors = 0;  goto nxthdr;
  1301.             }
  1302.             if (closeit()) {
  1303.                 tryzhdrtype = ZFERR;
  1304.                 vfile("rzfile: closeit returned <> 0");
  1305.                 return ERROR;
  1306.             }
  1307.             vfile("rzfile: normal EOF");
  1308.             return c;
  1309.         case ERROR:    /* Too much garbage in header search error */
  1310. #ifdef SEGMENTS
  1311.             putsec(secbuf, chinseg);
  1312.             chinseg = 0;
  1313. #endif
  1314.             if ( --n < 0) {
  1315.                 vfile("rzfile: zgethdr returned %d", c);
  1316.                 return ERROR;
  1317.             }
  1318.             zmputs(Attn);
  1319.             continue;
  1320.         case ZSKIP:
  1321. #ifdef SEGMENTS
  1322.             putsec(secbuf, chinseg);
  1323.             chinseg = 0;
  1324. #endif
  1325.             Modtime = 1;
  1326.             closeit();
  1327.             vfile("rzfile: Sender SKIPPED file");
  1328.             return c;
  1329.         case ZDATA:
  1330.             if (rclhdr(Rxhdr) != rxbytes) {
  1331.                 if ( --n < 0) {
  1332.                     return ERROR;
  1333.                 }
  1334. #ifdef SEGMENTS
  1335.                 putsec(secbuf, chinseg);
  1336.                 chinseg = 0;
  1337. #endif
  1338.                 zmputs(Attn);  continue;
  1339.             }
  1340. moredata:
  1341.             if (Verbose>1)
  1342.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1343.                   rxbytes, Crc32r?" CRC-32":"");
  1344. #ifdef SEGMENTS
  1345.             if (chinseg >= (1024 * SEGMENTS)) {
  1346.                 putsec(secbuf, chinseg);
  1347.                 chinseg = 0;
  1348.             }
  1349.             switch (c = zrdata(secbuf+chinseg, 1024))
  1350. #else
  1351.             switch (c = zrdata(secbuf, 1024))
  1352. #endif
  1353.             {
  1354.             case ZCAN:
  1355. #ifdef SEGMENTS
  1356.                 putsec(secbuf, chinseg);
  1357.                 chinseg = 0;
  1358. #endif
  1359.                 vfile("rzfile: zgethdr returned %d", c);
  1360.                 return ERROR;
  1361.             case ERROR:    /* CRC error */
  1362. #ifdef SEGMENTS
  1363.                 putsec(secbuf, chinseg);
  1364.                 chinseg = 0;
  1365. #endif
  1366.                 if ( --n < 0) {
  1367.                     vfile("rzfile: zgethdr returned %d", c);
  1368.                     return ERROR;
  1369.                 }
  1370.                 zmputs(Attn);
  1371.                 continue;
  1372.             case TIMEOUT:
  1373. #ifdef SEGMENTS
  1374.                 putsec(secbuf, chinseg);
  1375.                 chinseg = 0;
  1376. #endif
  1377.                 if ( --n < 0) {
  1378.                     vfile("rzfile: zgethdr returned %d", c);
  1379.                     return ERROR;
  1380.                 }
  1381.                 continue;
  1382.             case GOTCRCW:
  1383.                 n = 20;
  1384. #ifdef SEGMENTS
  1385.                 chinseg += Rxcount;
  1386.                 putsec(secbuf, chinseg);
  1387.                 chinseg = 0;
  1388. #else
  1389.                 putsec(secbuf, Rxcount);
  1390. #endif
  1391.                 rxbytes += Rxcount;
  1392.                 stohdr(rxbytes);
  1393.                 zshhdr(4,ZACK, Txhdr);
  1394.                 sendline(XON);
  1395.                 goto nxthdr;
  1396.             case GOTCRCQ:
  1397.                 n = 20;
  1398. #ifdef SEGMENTS
  1399.                 chinseg += Rxcount;
  1400. #else
  1401.                 putsec(secbuf, Rxcount);
  1402. #endif
  1403.                 rxbytes += Rxcount;
  1404.                 stohdr(rxbytes);
  1405.                 zshhdr(4,ZACK, Txhdr);
  1406.                 goto moredata;
  1407.             case GOTCRCG:
  1408.                 n = 20;
  1409. #ifdef SEGMENTS
  1410.                 chinseg += Rxcount;
  1411. #else
  1412.                 putsec(secbuf, Rxcount);
  1413. #endif
  1414.                 rxbytes += Rxcount;
  1415.                 goto moredata;
  1416.             case GOTCRCE:
  1417.                 n = 20;
  1418. #ifdef SEGMENTS
  1419.                 chinseg += Rxcount;
  1420. #else
  1421.                 putsec(secbuf, Rxcount);
  1422. #endif
  1423.                 rxbytes += Rxcount;
  1424.                 goto nxthdr;
  1425.             }
  1426.         }
  1427.     }
  1428. }
  1429.  
  1430. /*
  1431.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1432.  *   and \335 (break signal)
  1433.  */
  1434. zmputs(s)
  1435. char *s;
  1436. {
  1437.     register c;
  1438.  
  1439.     while (*s) {
  1440.         switch (c = *s++) {
  1441.         case '\336':
  1442.             sleep(1); continue;
  1443.         case '\335':
  1444.             sendbrk(); continue;
  1445.         default:
  1446.             sendline(c);
  1447.         }
  1448.     }
  1449. }
  1450.  
  1451. /*
  1452.  * Close the receive dataset, return OK or ERROR
  1453.  */
  1454. closeit()
  1455. {
  1456.     time_t time();
  1457.  
  1458. #ifndef vax11c
  1459.     if (Topipe) {
  1460.         if (pclose(fout)) {
  1461.             return ERROR;
  1462.         }
  1463.         return OK;
  1464.     }
  1465. #endif
  1466.     if (fclose(fout)==ERROR) {
  1467.         fprintf(stderr, "file close ERROR\n");
  1468.         return ERROR;
  1469.     }
  1470. #ifndef vax11c
  1471.     if (Modtime) {
  1472.         timep[0] = time(NULL);
  1473.         timep[1] = Modtime;
  1474.         utime(Pathname, timep);
  1475.     }
  1476. #endif
  1477.     if ((Filemode&S_IFMT) == S_IFREG)
  1478.         chmod(Pathname, (07777 & Filemode));
  1479.     return OK;
  1480. }
  1481.  
  1482. /*
  1483.  * Ack a ZFIN packet, let byegones be byegones
  1484.  */
  1485. ackbibi()
  1486. {
  1487.     register n;
  1488.  
  1489.     vfile("ackbibi:");
  1490.     Readnum = 1;
  1491.     stohdr(0L);
  1492.     for (n=3; --n>=0; ) {
  1493.         purgeline();
  1494.         zshhdr(4,ZFIN, Txhdr);
  1495.         switch (readline(100)) {
  1496.         case 'O':
  1497.             readline(1);    /* Discard 2nd 'O' */
  1498.             vfile("ackbibi complete");
  1499.             return;
  1500.         case RCDO:
  1501.             return;
  1502.         case TIMEOUT:
  1503.         default:
  1504.             break;
  1505.         }
  1506.     }
  1507. }
  1508.  
  1509.  
  1510.  
  1511. /*
  1512.  * Local console output simulation
  1513.  */
  1514. bttyout(c)
  1515. {
  1516.     if (Verbose || Fromcu)
  1517.         putc(c, stderr);
  1518. }
  1519.  
  1520. #ifndef vax11c
  1521. /*
  1522.  * Strip leading ! if present, do shell escape. 
  1523.  */
  1524. sys2(s)
  1525. register char *s;
  1526. {
  1527.     if (*s == '!')
  1528.         ++s;
  1529.     return system(s);
  1530. }
  1531. /*
  1532.  * Strip leading ! if present, do exec.
  1533.  */
  1534. exec2(s)
  1535. register char *s;
  1536. {
  1537.     if (*s == '!')
  1538.         ++s;
  1539.     mode(0);
  1540.     execl("/bin/sh", "sh", "-c", s);
  1541. }
  1542. #endif
  1543. /* End of rz.c */
  1544.